﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;

namespace WCYCReader.Utility.SocketHelper
{
    public class CommonHelper
    {
        #region JSON序列化和反序列化
        /// <summary>  
        /// JSON序列化  
        /// </summary>  
        public static string JsonSerializer<T>(T t)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
            MemoryStream ms = new MemoryStream();
            ser.WriteObject(ms, t);
            byte[] buffer = ms.ToArray();
            string jsonString = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
            ms.Close();
            return jsonString;
        }

        /// <summary>  
        /// JSON反序列化  
        /// </summary>  
        public static T JsonDeserialize<T>(string jsonString)
        {
            T jsonObject;
            DataContractJsonSerializer jsonSel = new DataContractJsonSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            using (StreamWriter sw = new StreamWriter(ms))
            {
                sw.Write(jsonString);
                sw.Flush();
                ms.Position = 0;
                jsonObject = (T)jsonSel.ReadObject(ms);

                sw.Dispose();
                ms.Dispose();
            }

            return jsonObject;
        }
        #endregion

        #region 数据转换
        /// <summary>
        /// 套接字发送和接收到的流都分别为两部分，前 500 字节为消息头，后面为消息体
        /// </summary>
        const int HeaderLength = 500;
        const int FileLength = 1024 * 1024 * 4; // 文件最长 4MB
        //const int MsgLength = 1024 * 2; // 消息文本最长字节数

        /// <summary>
        /// 把数据类型作为 head，把文字或文件数据作为 body，返回两者 byte[] 的组合结果
        /// </summary>
        /// <param name="dataType">作为 head，指示 body 的数据类型</param>
        /// <param name="strPath">文件的路径，文字或文件只穿递一个，另一个为 null</param>
        /// <param name="strMsg">文字的内容</param>
        /// <returns></returns>
        public static byte[] ConvertDataToByte(DataType dataType, string strPath, string strMsg)
        {
            byte[] byteResult;

            if (dataType.IsFile == true)
            {
                dataType.Exten = Path.GetExtension(strPath);
                dataType.FileName = Path.GetFileNameWithoutExtension(strPath);

                if (CommonHelper.Text_Length(dataType.Exten) > 41) // 后缀名中包含一个 .
                {
                    throw new Exception("文件的后缀名，长度不能超过20个汉字字符（40个英文字符）");
                }

                if (CommonHelper.Text_Length(dataType.FileName) > 200)
                {
                    throw new Exception("文件的名称，长度不能超过100个汉字字符（200个英文字符）");
                }

                // 消息头
                string strHeader = CommonHelper.JsonSerializer<DataType>(dataType);
                byte[] byteHeader = Encoding.UTF8.GetBytes(strHeader + "<EOF>");


                //通过文件流 读取文件内容
                using (FileStream fs = new FileStream(strPath, FileMode.OpenOrCreate))
                {
                    // 消息体
                    byte[] arrFile = new byte[FileLength];

                    //读取文件内容到字节数组，并 获得 实际文件大小
                    int fileLength = fs.Read(arrFile, 0, arrFile.Length);

                    byteResult = new byte[HeaderLength + fileLength];

                    Buffer.BlockCopy(byteHeader, 0, byteResult, 0, byteHeader.Length);
                    Buffer.BlockCopy(arrFile, HeaderLength, byteResult, HeaderLength, fileLength);
                }
            }
            else
            {
                // 消息头
                string strHeader = CommonHelper.JsonSerializer<DataType>(dataType);
                byte[] byteHeader = Encoding.UTF8.GetBytes(strHeader + "<EOF>");


                byte[] byteMsg = Encoding.UTF8.GetBytes(strMsg);
                byteResult = new byte[HeaderLength + byteMsg.Length];

                Buffer.BlockCopy(byteHeader, 0, byteResult, 0, byteHeader.Length);
                Buffer.BlockCopy(byteMsg, 0, byteResult, HeaderLength, byteMsg.Length);
            }

            return byteResult;
        }

        /// <summary>
        /// 如果有文件的 byte[] 数组，则不需要上面的方法，直接把 head 和 文件的 byte[] 组合在一起
        /// </summary>
        /// <param name="dataType">body 的数据类型</param>
        /// <param name="bytesFile">文件的 byte[] 数组</param>
        /// <returns></returns>
        public static byte[] ConvertFileToByte(DataType dataType, byte[] bytesFile)
        {
            byte[] byteResult;

            if (CommonHelper.Text_Length(dataType.Exten) > 41) // 后缀名中包含一个 .
            {
                throw new Exception("文件的后缀名，长度不能超过20个汉字字符（40个英文字符）");
            }

            if (CommonHelper.Text_Length(dataType.FileName) > 200)
            {
                throw new Exception("文件的名称，长度不能超过100个汉字字符（200个英文字符）");
            }

            // 消息头
            string strHeader = CommonHelper.JsonSerializer<DataType>(dataType);
            byte[] byteHeader = Encoding.UTF8.GetBytes(strHeader + "<EOF>");


            byteResult = new byte[HeaderLength + bytesFile.Length];

            Buffer.BlockCopy(byteHeader, 0, byteResult, 0, byteHeader.Length);
            Buffer.BlockCopy(bytesFile, 0, byteResult, HeaderLength, bytesFile.Length);

            return byteResult;
        }

        /// <summary>
        /// 转换源 byte[] 数据内容，获取其中的 head 和 body 的实际内容
        /// </summary>
        /// <param name="byteSrc">数据源</param>
        /// <param name="dataType">指示 body 的数据类型返回结果</param>
        /// <param name="byteFile">文件内容返回结果</param>
        /// <param name="strMsg">文字内容返回结果</param>
        public static void ConvertByteToData(byte[] byteSrc, out DataType dataType, out byte[] byteFile, out string strMsg)
        {
            dataType = null;
            byteFile = null;
            strMsg = null;

            byte[] byteHeader = new byte[HeaderLength];
            Buffer.BlockCopy(byteSrc, 0, byteHeader, 0, HeaderLength);
            string strHeader = Encoding.UTF8.GetString(byteHeader, 0, byteHeader.Length);

            if (strHeader.Contains("<EOF>"))
            {
                int index = strHeader.IndexOf("<EOF>");
                string strHeaderValue = strHeader.Substring(0, index);

                dataType = CommonHelper.JsonDeserialize<DataType>(strHeaderValue);
                if (dataType != null)
                {
                    if (dataType.IsFile == true)
                    {
                        byteFile = new byte[byteSrc.Length - HeaderLength];
                        Buffer.BlockCopy(byteSrc, HeaderLength, byteFile, 0, byteSrc.Length - HeaderLength);
                    }
                    else
                    {
                        byte[] byteMsg = new byte[byteSrc.Length - HeaderLength];
                        Buffer.BlockCopy(byteSrc, HeaderLength, byteMsg, 0, byteSrc.Length - HeaderLength);

                        strMsg = Encoding.UTF8.GetString(byteMsg, 0, byteMsg.Length);
                        strMsg = strMsg.Trim('\0');
                    }
                }
            }
        }

        #endregion

        #region 独立存储操作
        /// <summary>
        /// 把服务器端传来的文件保存到这个文件夹中
        /// </summary>
        public static string FolderName = "Folder";

        /// <summary>
        /// 把 byte[] 文件，存储到本地
        /// </summary>
        /// <param name="strFileName">文件名称</param>
        /// <param name="fileBytes">文件的实际数据</param>
        /// <returns></returns>
        public static async Task SaveFile(string strFileName, byte[] fileBytes)
        {

            StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;

            StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(FolderName, CreationCollisionOption.OpenIfExists);

            StorageFile file = await folder.CreateFileAsync(strFileName, CreationCollisionOption.ReplaceExisting);

            using (var s = await file.OpenStreamForWriteAsync())
            {
                s.Write(fileBytes, 0, fileBytes.Length);
            }

        }

        /// <summary>
        /// 根据文件名，获取独立存储里面的文件
        /// </summary>
        /// <param name="strFileName"></param>
        /// <returns></returns>
        public static async Task<StorageFile> ReadFile(string strFileName)
        {
            StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;

            StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(FolderName, CreationCollisionOption.OpenIfExists);

            return await folder.GetFileAsync(strFileName);
        }

        /// <summary>
        /// 扫描独立存储，获取指定文件夹中的所有文件
        /// </summary>
        /// <returns></returns>
        public static async Task<IReadOnlyList<StorageFile>> ScanFiles()
        {
            StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;

            StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(FolderName, CreationCollisionOption.OpenIfExists);

            return await folder.GetFilesAsync();
        }
        #endregion

        #region  计算文本长度
        /// <summary>   
        /// 计算文本长度，区分中英文字符，中文算两个长度，英文算一个长度
        /// </summary>
        /// <param name="Text">需计算长度的字符串</param>
        /// <returns>int</returns>
        public static int Text_Length(string Text)
        {
            int len = 0;

            for (int i = 0; i < Text.Length; i++)
            {
                byte[] byte_len = System.Text.Encoding.UTF8.GetBytes(Text.Substring(i, 1));
                if (byte_len.Length > 1)
                    len += 2;  //如果长度大于1，是中文，占两个字节，+2
                else
                    len += 1;  //如果长度等于1，是英文，占一个字节，+1
            }

            return len;//len / 2 + len % 2;
        }
        #endregion
    }
}
